#include "cglwindow.h"
#include <GL/glu.h>

CGlWindow::CGlWindow(QWidget* parent) : QGLWidget(parent)
/*
         Если child, то Qt::FramelessWindowHint |Qt::WindowStaysOnTopHint
         по умолчанию, а setAttribute(Qt::WA_TranslucentBackground) (прозрачный фон окна)
         игнорируется.
*/
 // :QGLWidget(0, 0, Qt::FramelessWindowHint/*|Qt::WindowStaysOnTopHint*/)
{
        QGLFormat fmt = format();
        setFormat(fmt);
}
void CGlWindow::initializeGL( )
{
    initializeOpenGLFunctions();
    glClearColor(0.5, 0.5, 0.5, 0.0);
    glShadeModel(/*GL_FLAT*/GL_SMOOTH);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    // Задание глобальных параметров освещения
    glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
    //	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
    float fmat[4] = { 0.7f, 0.7f, 0.7f, 1.f }; // Цвет материала (0-1.0)
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fmat);
    //	glEnable(GL_NORMALIZE);

    GLfloat light_ambient[] = { 0.f, 0.f, 0.f, 1.0f };
    GLfloat light_diffuse[] = { 0.5f, 0.5f, 0.5f, 1.0f };
    GLfloat light_specular[] = { 0.5f, 0.5f, 0.5f, 1.0f };
    GLfloat light_position[] = { 0.f, 0.f, 0.f, 1.f };
    glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // GL_NEAREST
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // GL_NEAREST
    // Indicate how the texture is to be applied to each pixel
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // GL_DECAL
}
void CGlWindow::resizeGL (int nWidth, int nHeight)
{
    if (!fds.GetAspectRatio(nWidth, nHeight, dx, dy)) return;
    fds.GetCenterBoundBox(&vc, r);
    // Проекция
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

//    glOrtho(-dx, dx, -dy, dy, r / 2., 4. * r);
    glFrustum(-dx, dx, -dy, dy, r / 2., 4. * r);

    // Взгляд
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(vc.X, vc.Y, vc.Z + 1.5 * r, vc.X, vc.Y, vc.Z, 1.0, 0.0, 0.0);
//    gluLookAt(fds.cam.pos[0], fds.cam.pos[1], fds.cam.pos[2], fds.cam.target[0], fds.cam.target[1], fds.cam.target[2],0.0, 1.0, 0.0);
}
void CGlWindow::paintGL ()
{
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glViewport(0, 0, (GLsizei)this->width(), (GLsizei)this->height());
    // Пока есть меши
    LPMESH pm = fds.pMesh;
    LPMATERIAL	pmat;
    while (pm) {
        // Установить указатель на массив точек меша
        if (pm->pvert) {
            glEnableClientState(GL_VERTEX_ARRAY);
            glVertexPointer(3, GL_FLOAT, 0, pm->pvert);
        }
        else glDisableClientState(GL_VERTEX_ARRAY);
        if(pm->ptvert) {
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
            glTexCoordPointer(2, GL_FLOAT, 0, pm->ptvert);
        }
        else glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        // Пока есть материл элементов поверхности меша
        LPMSHMAT pfmat;	// A list of faces that are assigned the material named
        unsigned short	j;		// Номер текущей поверхности (face)
        pfmat = pm->pmshmat;
        while (pfmat) {
            // Получить материал
            pmat = fds.GetMaterial(pfmat->name);
            // Установить материал элементов поверхности меша
            if (pmat) {
                if ((!pmat->img.isNull()) && pm->ptvert) { // Есть текстура
                    glEnable(GL_TEXTURE_2D);	// Включаем текстуру
                    glBindTexture(GL_TEXTURE_2D, texture);
                    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pmat->img.width(), pmat->img.height(),
                                 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid*)pmat->img.bits());
                }
                else {
                    glEnable(GL_LIGHTING);
                    float fmat[4];
                    if (pmat->pamb) {
                        fmat[0] = (float)pmat->pamb->R / 255.f;
                        fmat[1] = (float)pmat->pamb->G / 255.f;
                        fmat[2] = (float)pmat->pamb->B / 255.f;
                        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, fmat);
                    }
                    if (pmat->pdif) {
                        fmat[0] = (float)pmat->pdif->R / 255.f;
                        fmat[1] = (float)pmat->pdif->G / 255.f;
                        fmat[2] = (float)pmat->pdif->B / 255.f;
                        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fmat);
                    }
                    if(pmat->pspc) {
                        fmat[0] = (float)pmat->pspc->R/255.f;
                        fmat[1] = (float)pmat->pspc->G/255.f;
                        fmat[2] = (float)pmat->pspc->B/255.f;
                        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, fmat);
                    }
                    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, (GLfloat)100); // 0.7*128
                }
            }
            // Отобразить элементы поверхности меша
            for (unsigned short i = 0; i < pfmat->nface; i++) {
                if (pm->pnormal) glNormal3fv((GLfloat *)&pm->pnormal[i]); // Указать нормаль элемента
                j = pfmat->pface[i];
                if (pm->pvert) glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, &pm->pface[j]);
            }
            // Следующий материл меша
            glDisable(GL_TEXTURE_2D);
            pfmat = pfmat->pnext;
        }
        // Следующий меш
        pm = pm->pnext;
    }

    glDisable(GL_TEXTURE_2D);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glFlush();

//    glEnable (GL_BLEND);
//    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//    float i = 1;
//    glBegin(GL_QUADS);
//       glColor4f(1, 0, 0, 0.2);
//       glVertex2f(-i, i);
//       glColor4f(0, 1, 0, 0.2);
//       glVertex2f(i, i);
//       glColor4f(0, 0, 1, 0.2);
//       glVertex2f(i, -i);
//       glColor4f(1, 1, 1, 0.2);
//       glVertex2f(-i, -i);
//    glEnd();
}
